package edu.purdue.cs.cs505._final.server.impl;

import java.math.BigInteger;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Iterator;

import org.apache.axis2.context.ConfigurationContext;
import org.apache.axis2.context.MessageContext;

import edu.purdue.cs.cs505._final.server.ReceiveSharing;
import edu.purdue.cs.cs505._final.server.ServerStub;
import edu.purdue.cs.cs505._final.server.WSParentIndex;
import edu.purdue.cs.cs505._final.server.WSShare;
import edu.purdue.cs.ds.ServerSets;
import edu.purdue.cs.ds.vss.Constants;
import edu.purdue.cs.ds.vss.Generator;
import edu.purdue.cs.ds.vss.IndexSets;
import edu.purdue.cs.ds.vss.ParentIndex;
import edu.purdue.cs.ds.vss.Share;
import edu.purdue.cs.ds.vss.ShareStore;
import edu.purdue.cs.ds.vss.VerifiableSharing;

public class ServerImpl {
	
	public ShareStore getPrimaryStore() {
		return getServiceStore();
	}

	public void addShare(WSShare share) {
		
		ShareStore store = getServiceStore();
		
		ParentIndex pi = getParentIndex(share.getParentIndex());
		Share s = new Share(new BigInteger(share.getShareValue()), share.getIndex(), pi);
		
		System.out.println(getServiceName() + " updated with " + s);
		store.update(s);
	}

	public void refresh(int n, int k) {
			
		ShareStore store = getServiceStoreCopyAndClear();
		String name = getServiceName();
		int id = Integer.parseInt(name.substring(name.length() - 1));
		
		ServerSets serverSets = new ServerSets(n, k);
		int l = serverSets.getL();
		ArrayList<ArrayList<Integer>> sets = serverSets.constructServerSets();
		
		
		ArrayList<Share> tmpShares = store.getShares();
		
		for (Iterator<Share> iterator = tmpShares.iterator(); iterator.hasNext();) { //For each share
			Share share = iterator.next(); //This is the parent share now
			ParentIndex pi = new ParentIndex(id, share.getIndex(), share.getParentIndex());
			
			SecureRandom sr = new SecureRandom();
			BigInteger r =  new BigInteger(Constants.q.bitLength() - 1, sr);
			
			
			//Do sub sharing
			Generator tmpG = new Generator(share.getS(), r , l);
			VerifiableSharing tmpVs = tmpG.generateVerifiableSharing();
			ArrayList<BigInteger> tmpSh = tmpVs.getS();
			ArrayList<Share> tmpShareList = new ArrayList<Share>();
			for(int j = 0; j < tmpSh.size(); j ++) {
				tmpShareList.add(new Share(tmpSh.get(j), j, pi));
			}
	
			IndexSets is = new IndexSets();
			ArrayList<ArrayList<Share>> tmpServerShares = is.generateShareSets2(n, tmpShareList, sets);
			//Send server shares in each service
			for(int j = 0; j < n; j ++) {
				System.out.println("Shares of service : " + j);
				ArrayList<Share> tmpShList = tmpServerShares.get(j);
				for (Iterator<Share> it = tmpShList.iterator(); it.hasNext();) {
					Share tmp = it.next();
					//Send temp to service
					
					try {
						ServerStub stub = new ServerStub("http://localhost:8080/axis2/services/server" + j);

						WSShare wss = new WSShare();
						wss.setParentIndex(convertPI(tmp.getParentIndex()));
						wss.setIndex(tmp.getIndex());
						wss.setShareValue(tmp.getS().toString());
						
						ReceiveSharing sharingInput = new ReceiveSharing();
						sharingInput.setReceiveSharing(wss);
						
						stub.receiveSharing(sharingInput);
						
					} catch (Exception e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					
					
				}
			}
		}
		
		System.out.println("\n\n" + name + " DONE!!!!\n\n");
	}
	
	
	private ShareStore getServiceStoreCopyAndClear() {
		ShareStore store = getServiceStore();
		
		String serviceName = getServiceName();
		MessageContext msgCtx = MessageContext.getCurrentMessageContext();
		ConfigurationContext configurationContext =  msgCtx.getServiceContext().getConfigurationContext();
		configurationContext.setProperty(serviceName + "-store", new ShareStore());
		
//		System.out.println(serviceName);
		return store;
	}
	
	private ShareStore getServiceStore() {
		ShareStore store = null;
		String serviceName = getServiceName();
		MessageContext msgCtx = MessageContext.getCurrentMessageContext();
		ConfigurationContext configurationContext =  msgCtx.getServiceContext().getConfigurationContext();
		Object stObj = configurationContext.getProperty(serviceName + "-store");
		if(stObj == null) {
			//Create a store
			store = new ShareStore();
			configurationContext.setProperty(serviceName + "-store", store);
		} else {
			store = (ShareStore) stObj;
		}
		
//		System.out.println(serviceName);
		return store;
	}

	private String getServiceName() {
		MessageContext msgContext = MessageContext.getCurrentMessageContext();  
		String serviceName = msgContext.getAxisService().getName();
		return serviceName;
	}
	
	private ParentIndex getParentIndex(WSParentIndex wsPi) {
		ParentIndex parent = null;
		if(wsPi.getParent() != null) {
			parent = getParentIndex(wsPi.getParent());
		}
		
		return new ParentIndex(wsPi.getServer(), wsPi.getIndex(), parent);		
	}
	

	private WSParentIndex convertPI(ParentIndex pi) {
		WSParentIndex parent = null;
		ParentIndex piParent = pi.getParent();
		if(piParent != null) {
			parent = convertPI(piParent);
		}
		WSParentIndex wsPi = new WSParentIndex();
		wsPi.setIndex(pi.getIndex());
		wsPi.setServer(pi.getServer());
		wsPi.setParent(parent);

		return wsPi;
	}

}
